// cpppython.cpp : Defines the entry point for the console application.
//

#include "cpppython.hpp"

using namespace dynamic::python;

namespace
{
	class pylock
	{
		pylock(const pylock&);
	public:
		pylock()  { PyEval_AcquireLock(); }
		~pylock() { PyEval_ReleaseLock(); }
	};
}


void dynamic::python::throw_exceptions()
{
	PyObject * error = PyErr_Occurred();

	if(error)
	{
		Py_INCREF(error);
		var error_var = py_to_var(error);
		PyErr_Clear();
		throw error_var;
		// throw exception("python_exception", "Python raised an exception", error_var);
	}
}


namespace dynamic
{
	var python_int(var interp, var i)
	{
		pylock l;
		return py_to_var( PyInt_FromLong(i.as_int()) );
	}

	var python_bool(var interp, var b)
	{
		pylock l;
		return py_to_var( b ? Py_True : Py_False );
	}

	var python_double(var interp, var d)
	{
		pylock l;
		return py_to_var( PyFloat_FromDouble(d.as_double()) );
	}

	var python_string(var interp, var s)
	{
		std::string str = s.as_string();
		pylock l;
		return py_to_var( PyString_FromStringAndSize(str.c_str(), str.size()));
	}

	var python_wstring(const std::wstring & str)
	{
		pylock l;
		return null; // python_object( PyString_FromStringAndSize(str.c_str(), str.size());
	}

	var python_eval(var interp, var cmd)
	{
		pylock l;	 // !! Re-entrancy ??

		PyObject * retval = PyRun_String(cmd.as_string().c_str(), Py_eval_input, Py_None, Py_None );		
		throw_exceptions();
		return py_to_var(retval);
	}

	var eval_with_env(var interp, var cmd, var globals, var locals)
	{
		pylock l;	 // !! Re-entrancy ??

		// Exceptions safety?
		var ret = py_to_var(
			PyRun_String(cmd.as_string().c_str(), Py_eval_input, var_to_py(globals), var_to_py(locals) ) );

		throw_exceptions();

		return ret;
	}

	var eval_source_env(var interp, var cmd, var globals)
	{
		pylock l;	 // !! Re-entrancy ??

		// Exceptions safety?
		var ret = py_to_var( PyRun_String(cmd.as_string().c_str(), Py_single_input, var_to_py(globals), Py_None ) );

		throw_exceptions();

		return ret;
	}

	var python_main()
	{
		char * argv[] = { "abc" };
		return Py_Main(sizeof(argv)/sizeof(argv[0]), argv);
	}


	var python_interpreter()
	{
		if(!Py_IsInitialized()) Py_Initialize();
		// PyEval_InitThreads();

		// ??
		// PyEval_ReleaseLock();

		return object("python_interpreter").extend
			("eval", python_eval)
			("eval_env", eval_with_env)
			("eval_source_env", eval_source_env)
			("create_bool", python_bool)
			("create_int", python_int)
			("create_double", python_double)
			("create_string", python_string)
			("main", python_main);
	}
}
